
package com.xyq.fs.views;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.HashMap;
import java.util.HashSet;

import java.util.Map;
import java.util.Set;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.xyq.fs.base.MyDirectoryS;

import com.xyq.fs.constants.IndexStringConstants;
import com.xyq.fs.constants.ParseConstant;
import com.xyq.fs.contants.filesuffixes2.ExcelEnums;
import com.xyq.fs.contants.filesuffixes2.PdfEnums;
import com.xyq.fs.contants.filesuffixes2.PptEnums;
import com.xyq.fs.contants.filesuffixes2.TxtEnums;
import com.xyq.fs.contants.filesuffixes2.WordEnums;

import com.xyq.fs.scan.ScanFileInf;
import com.xyq.fs.search.MySearch;
import com.xyq.fs.search.MySearchBean;
import com.xyq.fs.search.SearchBody;
import com.xyq.fs.util.MyTimeUtil;
import com.xyq.fs.views.WindowsB;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;

import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;

import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;

import javafx.scene.layout.GridPane;

import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

@SuppressWarnings("unchecked")
public class WindowsGo extends Application {

	/***
	 * 基础常量
	 */
	private String TITLE_STR = "文件内容搜索工具 v4.0966  快如闪电~~";
	private int SCENE_WEIGHT = 632;
	private int scene_HIGH = 345;
	private String LabelA_STR = "关键词";
	private String LabelB_STR = "过滤词";
	private String LabelC_STR = "检索条件";
	private String LabelD_STR = "扫描设置";
	private String LabelE_STR = "时间范围";
	private String BtnA_STR = "搜 索";
	private String BtnB_STR = "重 置";
	private static String BtnC_STR = "扫描文件";
	private static String rbtnA_STR = "全新扫描 ";
	private static String rbtnB_STR = "精简模式 ";
	private static String rbtnC_STR = "自动模式";
	private int BTN_WEIGHT = 85;
	private int BTN_HIGH = 31;

	/**
	 * 需要跳过的
	 */
	public static Set<String> skipFilesMap;

	/**
	 * 基础组件
	 */
	private Label labelA = new Label(LabelA_STR);
	private Label labelB = new Label(LabelB_STR);
	private Label labelC = new Label(LabelC_STR);
	private Label labelD = new Label(LabelD_STR);
	private Label labelE = new Label(LabelE_STR);

	private static TextField txtfieldA = new TextField();
	private static TextField txtfieldB = new TextField();

	private Button btnA = new Button(BtnA_STR);
	private Button btnB = new Button(BtnB_STR);
	private static Button btnC = new Button(BtnC_STR);

	Background bkA = ImageUtil.getImgUrl("IMAGES\\0.jpg");

	public static ComboBox<String> cboxA = new ComboBox<String>();
	public static ComboBox<String> cboxB = new ComboBox<String>();
	public static ComboBox<String> cboxC = new ComboBox<String>();

	private static ProgressIndicator pinA = new ProgressIndicator();

	public static final RadioButton rbtnA = new RadioButton(rbtnA_STR);
	public static final RadioButton rbtnB = new RadioButton(rbtnB_STR);
	public static final RadioButton rbtnC = new RadioButton(rbtnC_STR);

	public static Text tsB = new Text("工具初始化中...");
	public static ImageCursor Mouse;
	public static Image ICON;
	public static Image imageA;
	private static Stage primaryStage;
	private static DatePicker startDate = new DatePicker();
	private static DatePicker endDate = new DatePicker();

	/**
	 * 应用变量
	 */
	public static int GO = 1;
	public static File[] DIRROOTS;
	public static int SLEEP_NOW = 0;
	public static ScanFileInf sf;
	public static int TASK_TIME = 10;
	private Stage cacheSate;
	private Path p;
	public static MySearchBean msb;
	public static Map<String, WindowsB> map;
	private Set<String> searchKeySet;

	@Override
	public void start(Stage primaryStage) throws Exception {

		Thread t = new Thread(() -> {
			Platform.runLater(() -> {
				// 3.根布局
				GridPane grid = new GridPane();
				Scene scene = new Scene(grid, SCENE_WEIGHT, scene_HIGH);
				scene.getStylesheets().add(WindowsGo.class.getResource("WindowsA.css").toExternalForm());

				// 4.关键词标签
				labelA.setPrefWidth(80);
				grid.add(labelA, 0, 1);

				// 5.关键词搜索框
				grid.add(txtfieldA, 1, 1);
				// txtfieldA.setFocusTraversable(false);

				// 6.搜索按钮
				btnA.setPrefSize(BTN_WEIGHT, BTN_HIGH);
				grid.add(btnA, 2, 1);

				// 7.添加背景图片
				grid.setBackground(bkA);

				// 8.过滤词标签
				grid.add(labelB, 0, 2);

				// 9.过滤词搜索框
				grid.add(txtfieldB, 1, 2);

				// 10.清除按钮
				btnB.setPrefSize(BTN_WEIGHT, BTN_HIGH);
				grid.add(btnB, 2, 2);

				// 11.检索条件标签
				grid.add(labelC, 0, 3);
				grid.add(labelE, 0, 4);
				grid.add(labelD, 0, 5);

				GridPane grid2 = new GridPane();
				grid.add(grid2, 1, 3);

				// 12.文件类型下拉框
				cboxA.setValue(IndexStringConstants.QBLX);
				cboxA.setId("cb1");
				grid2.add(cboxA, 0, 1);

				// 13.盘符下拉框
				cboxB.setId("cb1");
				cboxB.setValue(IndexStringConstants.SYPF);
				grid2.add(cboxB, 1, 1);

				cboxC.setId("cb1");
				cboxC.setValue(IndexStringConstants.WJMPX);
				grid2.add(cboxC, 2, 1);

				GridPane grid4 = new GridPane();
				grid.add(grid4, 1, 4);
				grid4.add(startDate, 1, 0);
				startDate.setPrefSize(136, 31);

				grid4.add(endDate, 2, 0);
				endDate.setPrefSize(136, 31);

				GridPane grid3 = new GridPane();
				grid.add(grid3, 1, 5);

				// 14.扫描按钮
				btnC.setPrefSize(98, BTN_HIGH);
				grid3.add(btnC, 6, 1);

				// 15.进度条
				pinA.setPrefSize(35, 35);
				grid3.add(pinA, 5, 1);

				// 16.全新扫描
				grid3.add(rbtnA, 2, 1);

				// 17.全新扫描
				rbtnB.setSelected(true);
				grid3.add(rbtnB, 3, 1);
				grid3.add(rbtnC, 4, 1);

				// ----------------样式属性区-------------------
				grid.setAlignment(Pos.CENTER);
				grid.setHgap(10);
				grid.setVgap(10);
				grid.setPadding(new Insets(39, 0, 0, 0));

				primaryStage.setScene(scene);
				tsB.setId("scanTs");
				grid.add(tsB, 1, 6);
				primaryStage.show();
				cacheSate = getStage();
				Mouse = new ImageCursor(ImageUtil.getImage("IMAGES\\3.png"), 0, 0);
				scene.setCursor(Mouse);
			});
		});
		t.setPriority(10);
		t.start();

		endDate.setId("dpp");
		startDate.setId("dpp");
		// 1.定义背景大小不可变更
		primaryStage.setResizable(false);
		// 2.标题
		primaryStage.setTitle(TITLE_STR);
		pinA.setVisible(false);

		msb = new MySearchBean();
		map = new HashMap<>();
		skipFilesMap = new HashSet<String>();
		searchKeySet = new HashSet<String>();

		// 15.提示词

		ICON = ImageUtil.getImage("IMAGES\\4.jpg");
		Platform.runLater(() -> {

			primaryStage.getIcons().add(ICON);
			imageA = ImageUtil.getImage("IMAGES\\1.jpg");
			MyDirectoryS.init();
			addSkip();
			txtfieldA.requestFocus();

			// 开启自动扫描
			p = Paths.get(System.getProperty("user.dir") + "\\CONF\\scan.txt");
			if (Files.exists(p)) {
				rbtnC.setSelected(true);
			}
		});
		ObservableList<String> optionsA = FXCollections.observableArrayList(IndexStringConstants.QBLX);
		ObservableList<String> optionsB = FXCollections.observableArrayList(IndexStringConstants.SYPF);
		ObservableList<String> optionsC = FXCollections.observableArrayList(IndexStringConstants.ASJPX);
		// --------属性绑定-------

		optionsA.addAll(WordEnums.getValues());
		optionsA.addAll(ExcelEnums.getValues());
		optionsA.addAll(PdfEnums.PDF);
		if (rbtnB.isSelected())
			optionsA.addAll(TxtEnums.getSimleValues());
		else
			optionsA.addAll(TxtEnums.getValues());
		optionsA.addAll(PptEnums.getValues());
		optionsA.addAll(IndexStringConstants.QT);
		optionsA.addAll(IndexStringConstants.QT2);

		optionsC.add(IndexStringConstants.WJMPX);

		cboxA.setItems(optionsA);
		cboxB.setItems(optionsB);
		cboxC.setItems(optionsC);
		DIRROOTS = File.listRoots();

		for (File drive : DIRROOTS) {
			optionsB.addAll((drive.toString().charAt(0) + "").toUpperCase());
		}

		txtfieldA.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				search();
			}
		});

		txtfieldA.textProperty().addListener(new ChangeListener<String>() {

			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {

				if (GO == 1) {
					tsB.setText("工具初始化中,请稍等...");
				} else {
					newValue = newValue.replaceAll("[a-z]{1,5}'.*", "");
					if (newValue.length() > 0) {
						if (searchKeySet.add(newValue)) {
							preLoadWB();
						}else preBody();
					} else {
						msb.setBody(null);
					}
				}
			}
		});

		txtfieldB.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				search();
			}
		});

		txtfieldB.textProperty().addListener(new ChangeListener<String>() {

			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {

				msb.setBody(getSearchBody());
			}
		});

		btnA.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				search();
			}
		});

		/**
		 * 重置按钮
		 */
		btnB.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				SLEEP_NOW = 4;
				txtfieldA.clear();
				txtfieldB.clear();
				startDate.setValue(null);
				endDate.setValue(null);
				cboxA.setValue(IndexStringConstants.QBLX);
				cboxB.setValue(IndexStringConstants.SYPF);
				tsB.setText("");
				rbtnA.setSelected(false);
				rbtnB.setSelected(true);
				msb.setBody(null);
				map.clear();
			}
		});
		cboxC.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				
				preLoadWB();
			}
		});

		btnC.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				autoScan();
			}
		});
		cboxA.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				msb.setBody(null);
			}
		});
		cboxB.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				msb.setBody(null);
			}
		});

		rbtnB.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				msb.setBody(null);
				if (rbtnB.isSelected()) {
					TASK_TIME = 15;
					TxtEnums.setRUN_TXT_SET(0);
					TxtEnums.getValues().forEach(s -> {
						if (!".TXT".equals(s)) {
							optionsA.remove(s);
						}
					});

				} else {
					TASK_TIME = 30;
					TxtEnums.setRUN_TXT_SET(1);
					TxtEnums.getValues().forEach(s -> {
						if (!".TXT".equals(s)) {
							optionsA.add(s);
						}
					});
				}
			}
		});

		rbtnC.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				if (rbtnC.isSelected()) {

					if (!Files.exists(p))
						try {
							Files.createFile(p);
						} catch (IOException e) {
							e.printStackTrace();
						}
				} else if (Files.exists(p)) {
					try {
						Files.delete(p);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});

		startDate.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				msb.setBody(null);
			}
		});

		endDate.setOnAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {

				msb.setBody(null);
			}
		});

		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {

			@Override
			public void handle(WindowEvent event) {

				writerSkip();
				SLEEP_NOW = 4;
				primaryStage.close();
				MyDirectoryS.commit();
				MyDirectoryS.closeAll();

				System.exit(0);
			}
		});

	}
    
	
	private void preBody(){
		
		new Thread(()->{
			SearchBody body = getSearchBody();
			msb.setBody(body);
		}).start();
	}
	private void preLoadWB() {
     
		new Thread(() -> {
			SearchBody body = getSearchBody();
			msb.setBody(body);
			Platform.runLater(() -> {
				try {
					WindowsB wb = new WindowsB(body, msb.getQuery());
					map.put(body.getCachePre(), wb);
					wb.start(cacheSate);
					cacheSate = getStage();
				} catch (Exception e) {
					e.printStackTrace();
				}
			});
		}).start();
	}

	public static void close2() {

		Platform.runLater(() -> {
			if (primaryStage != null)
				primaryStage.close();
		});
	}

	// -----------普通方法--------------------

	public static void preLoad() {

		msb.setBody(getSearchBody());
		WindowsB wb = new WindowsB(msb.getBody(), msb.getQuery());
		map.put(msb.getBody().getCachePre(), wb);
		Platform.runLater(() -> {
			try {
				wb.start(getStage());
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		ParseConstant.init();
	}

	/**
	 * 查询算法
	 */
	private static DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	private static String SP = " ";

	private static SearchBody getSearchBody() {

		SearchBody body = new SearchBody();
		String searchKey = txtfieldA.getText().replaceAll("\\s+", SP).trim().toLowerCase();
		String[] searchKeys = searchKey.split(SP);
		body.setSearchKey(searchKey);
		body.setSearchKeys(searchKeys);

		String nosearchKey = txtfieldB.getText().replaceAll("\\s+", SP).trim().toLowerCase();
		if (nosearchKey.length() > 0) {
			String[] nosearchKeys = nosearchKey.replaceAll("\\s+", SP).split(SP);
			body.setNoSearchKeys(nosearchKeys);
			body.setNoSearchKey(nosearchKey);
		}
		StringBuilder sbb = new StringBuilder().append(searchKey).append(body.getNoSearchKey()).append(cboxA.getValue())
				.append(cboxB.getValue()).append(cboxC.getValue()).append(rbtnA.isSelected()).append(rbtnB.isSelected())
				.append(startDate.getValue()).append(endDate.getValue());
		body.setCachePre(sbb.toString());

		if (startDate.getValue() != null && endDate.getValue() != null) {
			try {
				body.setStartDate(sdf.parse(startDate.getValue().toString()));
				body.setEndDate(sdf.parse(endDate.getValue().toString()));
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		sbb = null;
		return body;
	}

	private void search() {

		Platform.runLater(() -> {

			if (tsB.getText().indexOf("关") != -1)
				tsB.setText("");
			if (GO == 1) {
				tsB.setText("工具初始化中,请稍等...");
			} else {
				if (SLEEP_NOW == 4)
					SLEEP_NOW = 0;

				SearchBody body = msb.getBody();
				WindowsB wb;
				if (SLEEP_NOW == 0 && body != null) {
					if ("".equals(body.getSearchKey())) {
						tsB.setText("关键词不能为空");
						return;
					}
					try {
						wb = map.get(body.getCachePre());
						if (wb != null) {
							wb.show();
						} else {
							wb = new WindowsB(body, msb.getQuery());
							wb.start(cacheSate);
							wb.show();
							map.put(body.getCachePre(), wb);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else {
					body = getSearchBody();
					if ("".equals(body.getSearchKey())) {
						tsB.setText("关键词不能为空");
					} else {
						try {
							msb.setBody(body);
							wb = new WindowsB(msb.getBody(), msb.getQuery());
							wb.start(cacheSate);
							wb.show();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
				cacheSate = getStage();
			}
		});
	}

	public static void autoScan() {

		if (MyDirectoryS.writer == null) {
			MyAlert.alert("工具正在初始化中,请稍后再试!");
			return;
		}

		if (SLEEP_NOW == 0 || SLEEP_NOW == 4) {
			WindowsGo.tsB.setText("");
			SLEEP_NOW = 1;
			Platform.runLater(() -> {
				btnC.setText("扫描中");
				pinA.setVisible(true);
			});

			new Thread(() -> {

				long cha = sf.scan();
				SLEEP_NOW = 0;
				String chaStr = MyTimeUtil.formatTime(cha);

				Platform.runLater(() -> {
					btnC.setText("扫描文件");
					pinA.setVisible(false);
					if (tsB.getText().length() > 0) {
						if (rbtnA.isSelected()) {
							tsB.setText("全盘扫描完毕," + tsB.getText() + ",耗时" + chaStr);
						} else
							tsB.setText("全盘扫描完毕," + tsB.getText().replaceAll("已扫描的文件数量", "更新的文件数量") + ",耗时" + chaStr);
					} else {
						tsB.setText("全盘扫描完毕,耗时" + chaStr);
					}

					WindowsGo.msb.setBody(null);
					WindowsGo.map.clear();
					if (rbtnA.isSelected() || rbtnC.isSelected()) {
						// 此操作用后台线程处理,可减少最后显示时的卡顿
						new Thread(() -> {
							MySearch.delOld();
							MyDirectoryS.updates();
							WindowsGo.rbtnA.setSelected(false);
						}).start();
					} else {
						MyDirectoryS.updates();
					}
				});
			}).start();
		} else if (SLEEP_NOW == 1) {
			SLEEP_NOW = 2;
			btnC.setText("扫描暂停中");
			pinA.setVisible(false);
		} else if (SLEEP_NOW == 2) {
			btnC.setText("扫描中");
			SLEEP_NOW = 1;
			pinA.setVisible(true);
		}
	}

	private static Stage getStage() {

		Group root = new Group();
		root.getChildren().add(new ImageView(WindowsGo.imageA));
		Scene scene = new Scene(root, 758, 550);
		Stage stage = new Stage();
		stage.setScene(scene);
		stage.setResizable(false);
		stage.setTitle("搜索结果");
		stage.getIcons().add(WindowsGo.ICON);

		return stage;

	}

	private void addSkip() {

		Kryo kryo = new Kryo();
		File kf = new File(System.getProperty("user.dir") + "\\CONF\\aa");
		if (kf.exists()) {
			Input input;
			try {
				input = new Input(new FileInputStream(kf));
				skipFilesMap = kryo.readObject(input, HashSet.class);
				input.close();
				System.out.println("加载了" + skipFilesMap.size());
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

	public static void writerSkip() {

		Kryo kryo = new Kryo();
		File kf = new File(System.getProperty("user.dir") + "\\CONF\\aa");
		Output output;
		try {
			output = new Output(new FileOutputStream(kf));
			System.out.println("写入:" + skipFilesMap.size());
			kryo.writeObject(output, skipFilesMap);
			output.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {

		launch(args);
	}

}
